package org.appframe4gwt.server.persistance;

import xq.gwt.ui.crud.FilterModel;
import xq.sql.clauses.AndClause;
import xq.sql.clauses.CompositeClause;
import xq.sql.clauses.FieldValueClause;
import xq.sql.clauses.OrClause;
import xq.sql.clauses.WhereClause;
import xq.sql.factory.ValueBuilder;
import xq.sql.operators.EqualTo;
import xq.sql.operators.GreaterThanOrEquals;
import xq.sql.operators.In;
import xq.sql.operators.Is;
import xq.sql.operators.IsNot;
import xq.sql.operators.LessThanOrEquals;
import xq.sql.operators.Like;
import xq.sql.operators.NotEqualTo;
import xq.sql.operators.NotIn;
import xq.sql.operators.NotLike;
import xq.sql.terms.Clause;
import xq.sql.terms.Operator;
import xq.sql.terms.Value;

public class WhereClauseBuilder {
	public static  WhereClause build(FilterModel filter) throws Exception{		
		if(filter == null)
			return null;
		WhereClause clause = new WhereClause(buildFilterClause(filter));
		return clause;
	}
	
	private static Clause buildFilterClause(FilterModel filter) throws Exception{
		Clause filterClause = null;
		
		if(filter.isComposite()){
			CompositeClause compositeClause = null;
			switch (filter.getChildClauses().getListType()) {
			case AND:
				AndClause andClause = new AndClause();
				compositeClause = andClause;				
				break;					
            case OR:
				OrClause orClause = new OrClause();
				compositeClause = orClause;
				break;
			default:
				throw new Exception("Unknown composite clause type.");				
			}
			for (int i = 0; i < filter.getChildClauses().size(); i++) {
				Clause childClause = buildFilterClause(filter.getChildClauses().get(i));
				compositeClause.add(childClause);
			}
			filterClause = compositeClause;
			
		} else {	
			//Wildcard hack  
			if(xq.gwt.ui.crud.FilterModel.Operator.contains.equals(filter.getOperator())){
				filter.getFieldValue().setText("%" + filter.getFieldValue().getText() + "%");
			}
			
			Value val = ValueBuilder.valueOf(filter.getFieldValue());
			Operator op = fromUIOperator(filter.getOperator());			
			FieldValueClause fieldVal = new FieldValueClause(filter.getFieldValue().getName(), op, val);
			filterClause = fieldVal;			
		}
		return filterClause;
	}
	
	
	public static Operator fromUIOperator(xq.gwt.ui.crud.FilterModel.Operator uiOperator) throws Exception{
		switch (uiOperator) {
		case equals:
			return new EqualTo();			
		case notEquals:
			return new NotEqualTo();
		case from:
			return new GreaterThanOrEquals();			
		case to:
			return new LessThanOrEquals();
		case is:
			return new Is();
		case isNot:
			return new IsNot();
		case contains:
			return new Like();
		case NotContains:
			return new NotLike();
		case in:
			return new In();	
		case notIn:
			return new NotIn();
		case like:
			return new Like();
		case notLike:
			return new NotLike();
		default:
			throw new Exception("Unknown operator type " + uiOperator );			
		}
	}
	
	
}
